package com.huike.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.huike.dto.ReportPageDto;
import com.huike.entity.*;
import com.huike.mapper.*;
import com.huike.result.PageResult;
import com.huike.service.ReportService;
import com.huike.vo.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ReportServiceImpl implements ReportService {
    @Autowired
    private CustomerMapper customerMapper;
    @Autowired
    private SysDictDataMapper sysDictDataMapper;
    @Autowired
    private ContractMapper contractMapper;
    @Autowired
    private ClueMapper clueMapper;
    @Autowired
    private SaleMapper saleMapper;
    @Autowired
    private ChannelReportMapper channelReportMapper;
    @Autowired
    private ActivityMapper activityMapper;


    /**
     * 查询字典表
     *
     * @return Result<List < SysDictData>>
     */
    @Override
    public List<SysDictData> getSysDictData(String dictType) {
        return sysDictDataMapper.selectList(
                new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getDictType, dictType));
    }


    /**
     * 查询学科客户统计
     *
     * @param beginDate LocalDate
     * @param endDate   LocalDate
     * @return SubjectCustomerReportVo
     */
    @Override
    public SubjectCustomerReportVo subjectCustomerReport(LocalDate beginDate, LocalDate endDate) {
        //处理时间
        if (endDate == null) {
            endDate = LocalDate.now().minusDays(1);
        }
        if (beginDate == null) {
            beginDate = endDate.minusDays(6);
        }
        LocalDateTime minTime = LocalDateTime.of(beginDate, LocalTime.MIN);
        LocalDateTime maxTime = LocalDateTime.of(endDate, LocalTime.MAX);

        //查询所有学科
        List<SysDictData> sysDictDataList = getSysDictData("course_subject");
        //搜集所有学科的编号
        List<String> subjectList = sysDictDataList.stream().sorted(Comparator.comparing(SysDictData::getDictValue))
                .map(SysDictData::getDictValue).distinct().collect(Collectors.toList());
        //搜集所有学科的名称
        List<String> subjectDictLabelList = sysDictDataList.stream().sorted(Comparator.comparing(SysDictData::getDictValue))
                .map(SysDictData::getDictLabel).distinct().collect(Collectors.toList());

        //查询总客户数
        Integer totalCount = customerMapper.selectCount(new LambdaQueryWrapper<Customer>()
                .between(Customer::getCreateTime, minTime, maxTime));

        //查询学科客户数
        List<Integer> subjectCustomerList = new ArrayList<>();
        for (String subject : subjectList) {
            Integer subjectCount = customerMapper.selectCount(new LambdaQueryWrapper<Customer>()
                    .between(Customer::getCreateTime, minTime, maxTime)
                    .eq(Customer::getSubject, subject));
            subjectCustomerList.add(subjectCount);
        }

        return SubjectCustomerReportVo.builder()
                .subjectCustomerList(subjectCustomerList)
                .totalCustomer(totalCount)
                .subjectList(subjectDictLabelList).build();
    }


    /**
     * 客户统计查询
     *
     * @param beginDate LocalDate
     * @param endDate   LocalDate
     * @return CustomerReportVo
     */
    @Override
    public CustomerReportVo customerReport(LocalDate beginDate, LocalDate endDate) {
        //封装日期集合
        List<LocalDate> dateList = getDateList(beginDate, endDate);
        //封装客户数据
        List<Integer> totalCustomerList = new ArrayList<>();
        //封装每天新增客户数据
        List<Integer> newCustomerList = new ArrayList<>();

        for (LocalDate date : dateList) {
            LocalDateTime minTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime maxTime = LocalDateTime.of(date, LocalTime.MAX);

            //查询截止当天的总客户数
            LambdaQueryWrapper<Customer> lqw = new LambdaQueryWrapper<>();
            lqw.le(Customer::getCreateTime, maxTime);
            int totalCustomer = customerMapper.selectCount(lqw);

            //查询当天新增的用户数
            lqw.ge(Customer::getCreateTime, minTime);
            int newCustomer = customerMapper.selectCount(lqw);

            //封装进对应集合
            totalCustomerList.add(totalCustomer);
            newCustomerList.add(newCustomer);
        }

        //封装VO
        return CustomerReportVo.builder()
                .dateList(StringUtils.join(dateList, ","))
                .newCustomerList(StringUtils.join(newCustomerList, ","))
                .totalCustomerList(StringUtils.join(totalCustomerList, ","))
                .build();
    }


    /**
     * 客户统计分页搜索
     *
     * @param dto ReportPageDto
     * @return PageResult<Customer>
     */
    @Override
    public PageResult<Customer> customerReportSearch(ReportPageDto dto) {
        if (dto.getPage() == null) dto.setPage(1);
        if (dto.getPageSize() == null) dto.setPageSize(10);

        //构建查询条件
        LambdaQueryWrapper<Customer> lqw = new LambdaQueryWrapper<>();

        if (dto.getChannelSource() != null && !"".equals(dto.getChannelSource())) {
            lqw.eq(Customer::getChannelSource, dto.getChannelSource());
        }
        if (dto.getDeptName() != null && !"".equals(dto.getDeptName())) {
            lqw.like(Customer::getDeptName, dto.getDeptName());
        }
        if (dto.getBelonger() != null && !"".equals(dto.getBelonger())) {
            lqw.like(Customer::getBelonger, dto.getBelonger());
        }

        //分页查询
        Page<Customer> selectPage = customerMapper.selectPage(new Page<>(dto.getPage(), dto.getPageSize()), lqw);

        return new PageResult<>(selectPage.getTotal(), selectPage.getRecords());
    }


    /**
     * 销售额统计
     *
     * @param beginDate LocalDate
     * @param endDate   LocalDate
     * @return SaleReportVo
     */
    @Override
    public SaleReportVo saleReport(LocalDate beginDate, LocalDate endDate) {
        //封装日期集合
        List<LocalDate> dateList = getDateList(beginDate, endDate);
        //封装每天销售额数据
        List<Double> newSaleList = new ArrayList<>();
        for (LocalDate date : dateList) {
            LocalDateTime minTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime maxTime = LocalDateTime.of(date, LocalTime.MAX);

            List<Map<String, Object>> mapList = contractMapper.selectMaps(new QueryWrapper<Contract>()
                    .select("IFNULL(sum(contract_order),0) as totalPrice")
                    .between("create_time", minTime, maxTime));
            Double totalPrice = (Double) mapList.get(0).get("totalPrice");

            newSaleList.add(totalPrice);
        }
        //封装VO
        return SaleReportVo.builder()
                .dateList(dateList)
                .newSaleList(newSaleList)
                .build();
    }


    /**
     * 销售额统计分页查询
     *
     * @param dto ReportPageDto
     * @return PageResultPageResult
     */
    @Override
    public PageResult<Sale> saleReportSearch(ReportPageDto dto) {
        if (dto.getPage() == null) dto.setPage(1);
        if (dto.getPageSize() == null) dto.setPageSize(10);

        //构建查询条件
        LambdaQueryWrapper<Sale> lqw = new LambdaQueryWrapper<>();

        if (dto.getDeptName() != null && !"".equals(dto.getDeptName())) {
            lqw.eq(Sale::getDeptName, dto.getDeptName());
        }
        lqw.orderByDesc(Sale::getAmount);
        //分页查询
        Page<Sale> salePage = saleMapper.selectPage(new Page<>(dto.getPage(), dto.getPageSize()), lqw);
        //返回
        return new PageResult<>(salePage.getTotal(), salePage.getRecords());
    }

    /**
     * 线索统计
     *
     * @param beginDate beginDate
     * @param endDate   endDate
     * @return endDate
     */
    @Override
    public ClueReportVo clueReport(LocalDate beginDate, LocalDate endDate) {
        //封装日期集合
        List<LocalDate> dateList = getDateList(beginDate, endDate);
        //封装线索总量数据
        List<Integer> totalClueList = new ArrayList<>();
        //封装每天新增线索数据
        List<Integer> newClueList = new ArrayList<>();

        for (LocalDate date : dateList) {
            LocalDateTime minTime = LocalDateTime.of(date, LocalTime.MIN);
            LocalDateTime maxTime = LocalDateTime.of(date, LocalTime.MAX);

            //查询截止当天的线索总量
            LambdaQueryWrapper<Clue> lqw = new LambdaQueryWrapper<>();
            lqw.le(Clue::getCreateTime, maxTime);
            int totalClue = clueMapper.selectCount(lqw);

            //查询当天新增线索
            lqw.ge(Clue::getCreateTime, minTime);
            int newClue = clueMapper.selectCount(lqw);

            //封装进对应集合
            totalClueList.add(totalClue);
            newClueList.add(newClue);
        }

        return ClueReportVo.builder()
                .dateList(dateList)
                .totalClueList(totalClueList)
                .newClueList(newClueList)
                .build();
    }


    /**
     * 线索转化率统计
     *
     * @param beginDate LocalDate
     * @param endDate   LocalDate
     * @return ClueInvertVo
     */
    @Override
    public ClueInvertVo clueInvert(LocalDate beginDate, LocalDate endDate) {
        //处理时间
        if (endDate == null) endDate = LocalDate.now().minusDays(1);
        if (beginDate == null) beginDate = endDate.minusDays(6);
        LocalDateTime minDate = LocalDateTime.of(beginDate, LocalTime.MIN);
        LocalDateTime maxDate = LocalDateTime.of(endDate, LocalTime.MAX);

        //查询线索总数
        LambdaQueryWrapper<Clue> lqw = new LambdaQueryWrapper<>();
        lqw.between(Clue::getCreateTime, minDate, endDate);
        Integer clueTotal = clueMapper.selectCount(lqw);

        //查询有效线索总数
        lqw.eq(Clue::getIsPool, 0);
        Integer successClue = clueMapper.selectCount(lqw);

        //转化商机数
        Integer business = customerMapper.selectCount(new LambdaQueryWrapper<Customer>()
                .between(Customer::getCreateTime, minDate, maxDate));

        //转化客户数
        Integer successCustomer = contractMapper.selectCount(new LambdaQueryWrapper<Contract>()
                .between(Contract::getCreateTime, minDate, maxDate)
                .eq(Contract::getStatus, 4));

        return ClueInvertVo.builder().clueTotal(clueTotal).successClue(successClue)
                .successCustomer(successCustomer).business(business).build();
    }

    /**
     * 线索分页查询
     *
     * @param dto ReportPageDto
     * @return PageResult<Clue>
     */
    @Override
    public PageResult<Clue> clueReportSearch(ReportPageDto dto) {
        if (dto.getPage() == null) dto.setPage(1);
        if (dto.getPageSize() == null) dto.setPage(10);

        //构建查询条件
        LambdaQueryWrapper<Clue> lqw = new LambdaQueryWrapper<>();
        if (dto.getClueId() != null) {
            lqw.eq(Clue::getId, dto.getClueId());
        }
        if (dto.getDeptName() != null && !"".equals(dto.getDeptName())) {
            lqw.like(Clue::getDeptName, dto.getDeptName());
        }
        if (dto.getBelonger() != null && !"".equals(dto.getBelonger())) {
            lqw.like(Clue::getBelonger, dto.getBelonger());
        }

        Page<Clue> cluePage = clueMapper.selectPage(new Page<>(dto.getPage(), dto.getPageSize()), lqw);

        return new PageResult<>(cluePage.getTotal(), cluePage.getRecords());
    }


    /**
     * 渠道统计分页查询
     *
     * @param dto ReportPageDto
     * @return PageResult<ChannelReport>
     */
    @Override
    public PageResult<ChannelReport> channelReportSearch(ReportPageDto dto) {
        if (dto.getPage() == null) dto.setPage(1);
        if (dto.getPageSize() == null) dto.setPage(10);

        //构建查询条件
        LambdaQueryWrapper<ChannelReport> lqw = new LambdaQueryWrapper<>();
        if (dto.getActivityId() != null) {
            lqw.eq(ChannelReport::getActivityId, dto.getActivityId());
        }
        if (dto.getActivityName() != null && !"".equals(dto.getActivityName())) {
            lqw.like(ChannelReport::getActivityName, dto.getActivityName());
        }

        Page<ChannelReport> channelReportPage = channelReportMapper
                .selectPage(new Page<>(dto.getPage(), dto.getPageSize()), lqw);

        return new PageResult<>(channelReportPage.getTotal(), channelReportPage.getRecords());
    }


    /**
     * 渠道客户统计
     *
     * @param beginDate LocalDate
     * @param endDate   LocalDate
     * @return ChannelCustomerReportVo
     */
    @Override
    public ChannelCustomerReportVo channelReport(LocalDate beginDate, LocalDate endDate) {
        //处理时间
        if (endDate == null) endDate = LocalDate.now().minusDays(1);
        if (beginDate == null) beginDate = endDate.minusDays(6);
        LocalDateTime minDate = LocalDateTime.of(beginDate, LocalTime.MIN);
        LocalDateTime maxDate = LocalDateTime.of(endDate, LocalTime.MAX);

        //查询客户总数
        LambdaQueryWrapper<Clue> lqw = new LambdaQueryWrapper<Clue>().between(Clue::getCreateTime, minDate, maxDate);
        Integer customerTotal = clueMapper.selectCount(lqw);

        //查询所有渠道
        List<SysDictData> sysDictData = getSysDictData("clues_item");
        //搜集所有渠道的编号
        List<String> channelNums = sysDictData.stream().sorted(Comparator.comparing(SysDictData::getDictValue))
                .map(SysDictData::getDictValue).distinct().collect(Collectors.toList());
        //搜集所有渠道的名称
        List<String> channelNames = sysDictData.stream().sorted(Comparator.comparing(SysDictData::getDictValue))
                .map(SysDictData::getDictLabel).distinct().collect(Collectors.toList());

        //查询所有活动名称
        List<Activity> activities = activityMapper.selectList(null);
        //收集活动名称
        List<String> activityNames = activities.stream().map(Activity::getName).collect(Collectors.toList());

        //查询渠道客户数量
        List<Integer> channelCustomerNum = getChannelCustomerNum(channelNums, minDate, maxDate);
        //查询每个活动客户数量
        List<Integer> activityCustomerNum = getActivityCustomerNum(activityNames, minDate, maxDate);

        return ChannelCustomerReportVo.builder().totalCustomer(customerTotal)
                .activityNames(activityNames).activityCustomerNum(activityCustomerNum)
                .channelNames(channelNames).channelCustomerNum(channelCustomerNum)
                .build();
    }

    private List<Integer> getActivityCustomerNum(List<String> activityNames, LocalDateTime minDate, LocalDateTime maxDate) {
        List<Integer> activityCustomerNum = new ArrayList<>();
        if (!activityNames.isEmpty()) {
            for (String activityName : activityNames) {
                Integer channelCustoemr = clueMapper.selectCount(new LambdaQueryWrapper<Clue>()
                        .eq(Clue::getActivityName, activityName)
                        .between(Clue::getCreateTime, minDate, maxDate));
                activityCustomerNum.add(channelCustoemr);
            }
        }
        return activityCustomerNum;
    }

    private List<Integer> getChannelCustomerNum(List<String> channelNums, LocalDateTime minDate, LocalDateTime maxDate) {
        List<Integer> channelCustomerNum = new ArrayList<>();
        if (!channelNums.isEmpty()) {
            for (String channelNum : channelNums) {
                Integer channelCustoemr = clueMapper.selectCount(new LambdaQueryWrapper<Clue>()
                        .eq(Clue::getChannel, channelNum)
                        .between(Clue::getCreateTime, minDate, maxDate));
                channelCustomerNum.add(channelCustoemr);
            }
        }
        return channelCustomerNum;
    }


    /**
     * 用于封装日期集合
     */
    private List<LocalDate> getDateList(LocalDate beginDate, LocalDate endDate) {
        if (endDate == null) {
            endDate = LocalDate.now().minusDays(1);
        }
        if (beginDate == null) {
            beginDate = endDate.minusDays(6);
        }

        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(beginDate);
        while (!beginDate.equals(endDate)) {
            beginDate = beginDate.plusDays(1);
            dateList.add(beginDate);
        }
        return dateList;
    }
}
